package org.romzzz.gwtclassifieds.client.ui;

import java.util.List;

import org.romzzz.gwtclassifieds.client.data.CategoryBean;
import org.romzzz.gwtclassifieds.client.i18n.LocalizedMessages;
import org.romzzz.gwtclassifieds.client.i18n.LocalizedStrings;
import org.romzzz.gwtclassifieds.client.service.ClassifiedService;
import com.extjs.gxt.ui.client.Style;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.CheckBoxListView;
import com.extjs.gxt.ui.client.widget.MessageBox;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.toolbar.ToolBar;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;

/**
 * This is the category list that is displayed as a left panel. It is bound to a store and provides check boxes to alter content of the upper right panel.
 */
public class CategoryList extends ContentPanel {
	
	private ListStore<CategoryBean> store;
	private CheckBoxListView<CategoryBean> categoryList;
	private ClassifiedGrid classifiedGrid;
	
	private List<CategoryBean> currentlyChecked = null;
	
	private LocalizedStrings localizedStrings = GWT.create(LocalizedStrings.class);

	public CategoryList(final boolean adminMode) {
		super(new FitLayout());
		
		categoryList = new CheckBoxListView<CategoryBean>();
		categoryList.getSelectionModel().setSelectionMode(Style.SelectionMode.SINGLE);
		categoryList.setDisplayProperty("value");
		store = new ListStore<CategoryBean>();
		categoryList.setStore(store);
		final Button removeCategory = new Button(localizedStrings.removeCategory());
		if (adminMode) {
			final Button addCategory = new Button(localizedStrings.addCategory());
			addCategory.addSelectionListener(new SelectionListener<ButtonEvent>() {
				@Override
				public void componentSelected(ButtonEvent ce) {
					new StandardPrompt(localizedStrings.addCategory()) {
						public void onOK(String value) {
							if (value != null && value.length() > 0) {
								boolean exists = false ;
								for (CategoryBean bean: store.getModels()) {
									if (bean.getValue().equals(value)) {
										exists = true;
										break;
									}
								}
								if (exists) {
									LocalizedMessages localizedMessages = GWT.create(LocalizedMessages.class);
									MessageBox.alert(localizedStrings.error(), localizedMessages.existingCategory(value), null);
								} else {
									final MessageBox box = MessageBox.wait(localizedStrings.pleaseWait(), null, localizedStrings.addingCategory());
									ClassifiedService.App.getInstance().addCategory(new CategoryBean(value), new AsyncCallback<List<CategoryBean>>() {
										public void onFailure(Throwable caught) {
											box.close();
											MessageBox.alert(localizedStrings.error(), caught.toString(), null);
										}
										public void onSuccess(List<CategoryBean> result) {
											box.close();
											init(result);
										}
									});
								}
							}
						}
					}.show();
				}
			});
			removeCategory.addSelectionListener(new SelectionListener<ButtonEvent>() {
				@Override
				public void componentSelected(ButtonEvent ce) {
					final MessageBox box = MessageBox.wait(localizedStrings.pleaseWait(), null, localizedStrings.removingCategory());
					ClassifiedService.App.getInstance().removeCategory(categoryList.getSelectionModel().getSelectedItem(), new AsyncCallback<List<CategoryBean>>() {
						public void onFailure(Throwable caught) {
							box.close();
							MessageBox.alert(localizedStrings.error(), caught.toString(), null);
						}
						public void onSuccess(List<CategoryBean> result) {
							box.close();
							init(result);
						}
						
					});
				}
			});
			removeCategory.setEnabled(false);
			setHeaderVisible(false);
			ToolBar buttonBar = new ToolBar();
			buttonBar.add(addCategory);
			buttonBar.add(removeCategory);
			setTopComponent(buttonBar);
		} else {
			setHeaderVisible(true);
			setHeading(localizedStrings.categories());
		}
		
		ToolBar selectionBar = new ToolBar();
		Button selectAll = new Button(localizedStrings.checkAll(), new SelectionListener<ButtonEvent>() {
			@Override
			public void componentSelected(ButtonEvent ce) {
				changeAll(true);
			}
		});
		Button deselectAll = new Button(localizedStrings.uncheckAll(), new SelectionListener<ButtonEvent>() {
			@Override
			public void componentSelected(ButtonEvent ce) {
				changeAll(false);
			}
		});
		selectionBar.add(selectAll);
		selectionBar.add(deselectAll);
		setBottomComponent(selectionBar);
		add(categoryList);
		
		// this listener was removed due to redundancy with the onClick listener below
		/*categoryList.getSelectionModel().addSelectionChangedListener(new SelectionChangedListener<Category>() {
			public void selectionChanged(SelectionChangedEvent<Category> se) {
				if (adminMode) {
					removeCategory.setEnabled(categoryList.getSelectionModel().getSelectedItem() != null);
				}
			}
		});*/
		categoryList.addListener(Events.OnClick, new Listener<BaseEvent>() {
			public void handleEvent(BaseEvent be) {
				if (currentlyChecked == null || currentlyChecked.size() != getCheckedCategories().size()) {
					currentlyChecked = getCheckedCategories();
					classifiedGrid.refresh();
					if (adminMode) {
						removeCategory.setEnabled(categoryList.getSelectionModel().getSelectedItem() != null);
					}
				}
			}
		});
	}
	
	/**
	 * Change the state of all the check boxes
	 * 
	 * @param checkState true to checked, false to unchecked
	 */
	private void changeAll(boolean checkState) {
		for (CategoryBean cat:store.getModels()) {
			categoryList.setChecked(cat, checkState);
		}
		classifiedGrid.refresh();
	}
	
	/**
	 * Refresh the category list using RPC to retrieve all categories from the database. This method does not keep the previous check boxes state.
	 */
	public void refresh() {
		final MessageBox box = MessageBox.wait(localizedStrings.pleaseWait(), null, localizedStrings.loadingCategories());
		ClassifiedService.App.getInstance().getCategories(new AsyncCallback<List<CategoryBean>>() {
			public void onFailure(Throwable caught) {
				box.close();
				MessageBox.alert(localizedStrings.error(), caught.toString(), null);
			}
			public void onSuccess(List<CategoryBean> result) {
				box.close();
				init(result);
			}
		});
	}
	
	private void init(List<CategoryBean> categories) {
		store.removeAll();
		for (CategoryBean cat: categories) {
			store.add(cat);
		}
		changeAll(true);
		currentlyChecked = getCheckedCategories();
		classifiedGrid.refresh();
	}
	
	public List<CategoryBean> getCheckedCategories() {
		return categoryList.getChecked();
	}
	
	public List<CategoryBean> getAllCategories() {
		return store.getModels();
	}
	
	/**
	 * This method is used to add a reference to the classified grid that will have to be updated depending on the available and checked categories.
	 * 
	 * @param grid the classified grid
	 */
	public void setClassifiedGrid(ClassifiedGrid grid) {
		classifiedGrid = grid;
	}
	
}
